/*
 * List.cpp
 *
 *  Created on: Jul 5, 2012
 *      Author: s131705
 */

#include "List.h"
#include <sstream>

#include <stdio.h>
#include <stdlib.h>
using namespace std;

List::List()
{
	this->pipes = new list<Pipeline*>();
}

List::~List()
{
 	list<Pipeline*>::iterator it;
	 for( it = pipes->begin(); it != pipes->end(); it++ )
	 {
	 	delete(*it);
	 }
	delete pipes;
}

void List::execute()
{
	while ( hasPipe() )
	{
		Pipeline* pipe = popPipe();

		if(pipe->hadExitCommand())
			return;

		int pid = fork();
		if (pid == 0)
		{
			executePipe( pipe );
			exit( 0 );
		}
		else if (pid > 0)
		{
			int status =0;
			pid=wait(&status);
		}
	}
}

void List::executePipe(Pipeline* ccp, int nextpd)
{
	int pd[2];

	Command* cp = ccp->popCommand();
	if ( ccp->hasCommands() )
	{
		if ( pipe(pd) < 0 )
		{
			cerr << "Error creating pipe!";
			exit( -1 );
		}
			dup2( pd[0], 0 );
	}

	if (nextpd != 0)
	{
		dup2( nextpd, 1 );
	}

	int pid = fork();
	if (pid == 0)
	{
		if ( ccp->hasCommands() )
		{
			executePipe( ccp, pd[1] );
		}
		exit( 0 );
	}
	else if (pid > 0)
	{
		if ( ccp->hasCommands() )
		{
			close(pd[1]);
		}
		int status;
		pid = wait(&status);

		if ( cp->getIORedirectionInput() != "" )
		{
			int ifd;

			if ( (ifd = open(cp->getIORedirectionInput().c_str(), O_RDONLY)) < 0 )
			{
				cerr << "Error redirecting input!";
				exit( ifd );
			}

			dup2( ifd, 0 );
		}

		if ( cp->getIORedirectionOutput() != "" )
		{
			int ofd;

			if ( cp->getAppend() )
			{
				ofd = open( cp->getIORedirectionOutput().c_str(), O_APPEND | O_WRONLY | O_CREAT);
			}
			else
			{
				ofd = open( cp->getIORedirectionOutput().c_str(), O_TRUNC | O_WRONLY | O_CREAT);
			}

			if ( ofd < 0 )
			{
				cerr << "Error redirecting output!";
				exit( ofd );
			}

			dup2(ofd, 1);
		}

		vector<string>* args = cp->getArguments();
		const char* argv[ args->size()+2 ];
		argv[0] = cp->getName().c_str();
		for (unsigned int i=0; i<args->size(); i++)
		{
			argv[i+1] = args->at(i).c_str();
		}
		argv[ args->size()+1 ] = NULL;
		delete cp;
		cout << " start exec: " << argv[0] << endl;
		execvp( argv[0], (char* const*)argv );


		cerr << "execvp() failed!" << endl;
		exit(-1);
	}
	else
	{
		cerr << "fork() failed!" << endl;
		exit(-1);
	}
	exit(0);
}

Pipeline* List::popPipe()
{
	Pipeline* returnPipe = pipes->front();
	pipes->pop_front();
	return returnPipe;
}

string List::toString()
{
	stringstream ss (stringstream::in | stringstream::out);
	list<Pipeline*>::iterator it;
	for( it = pipes->begin(); it != pipes->end(); it++ )
	{
		//it->toString();
		ss << (*it)->toString() << endl;
	}
	return ss.str();
}
